
package pl.genapp.stocksense.libraries;

import java.util.ArrayList;

import pl.genapp.stocksense.others.LegendTypeChangeListener;
import pl.genapp.stocksense.others.StockSenseState;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.net.NetworkInfo.DetailedState;
import android.preference.PreferenceManager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

abstract public class SentGraph extends View {
	
	/**
	 * Listener do klikniec
	 */
	
	public static interface OnSentClickListener {
		
		void onSentClick(int sentNo);
		
	}
	
	/**
	 * Klasa standaryzujaca obsuge legend
	 */
	public class LegendRenderer {
		
		public static final int ROW_MARGIN = 0;
		protected Paint textPaint;
		protected int[] margin;
		protected int[] iconSize;
		protected int[] textMargin;
		protected String[] customLabels;
		protected SentGraph sentGraph;
		protected int deltaAngle = 0;
		
		/**
		 * 
		 * @param margin
		 *            top right bottom left
		 * @param iconSize
		 *            width height
		 * @param textMargin
		 *            top left
		 */
		public LegendRenderer(int[] margin, int[] iconSize, int[] textMargin, SentGraph sentGraph) {
			
			this.margin = margin;
			this.iconSize = iconSize;
			this.textMargin = textMargin;
			this.sentGraph = sentGraph;
			
			textPaint = new Paint();
			textPaint.setColor(Color.BLACK);
			textPaint.setAntiAlias(true);
			
		}
		
		void drawLegend(Canvas canvas) {
			
			if (sentGraph.getLegendType() == LegendTypes.RIGHT_SIDE)
				renderRightSideLegend(canvas);
			else if (sentGraph.getLegendType() == LegendTypes.AROUND) renderAroundLegend(canvas);
			
		}
		
		int getLegendWidth() {
			
			int minWidth = margin[3] + iconSize[0] + textMargin[1] + margin[1];
			
			int maxLabelSize = 0;
			
			for (String s : getGraphLabel()) {
				
				maxLabelSize = (int) Math.max(maxLabelSize, textPaint.measureText(s));
				
			}
			
			return minWidth + maxLabelSize;
			
		}
		
		int getLegendWidth(int i) {
			
			int minWidth = 0;
			
			String labels[] = getGraphLabel();
			
			return minWidth + (int) textPaint.measureText(labels[i]);
			
		}
		
		int getLegendRowHeight() {
			
			Rect bound = new Rect();
			textPaint.getTextBounds(getGraphLabel()[0], 0, getGraphLabel()[0].length(), bound);
			
			int sizeInside = Math.max(iconSize[1], bound.height());
			
			return sizeInside + margin[0] + margin[2];
			
		}
		
		String[] getGraphLabel() {
			
			if (customLabels != null) {
				
				return customLabels;
				
			} else {
				
				String[] label = new String[6];
				
				float[] sentValue = sentGraph.getSentValues();
				
				for (int i = 0; i < sentGraph.getNumberOfSentiments(); i++) {
					
					label[i] = String.valueOf(sentValue[i]) + " % ";
					
				}
				
				return label;
			}
			
		}
		
		void drawIcon(Canvas canvas, RectF frame, int sentNo) {
			
		}
		
		void renderRightSideLegend(Canvas canvas) {
			
			String[] label = getGraphLabel();
			
			for (int i = 0; i < NUMBER_OF_SENTIMENTS; i++) {
				
				Point frameStartPoint = getLegendCoor(i);
				
				// draw icon
				float frameIconStartX = frameStartPoint.x + margin[3];
				float frameIconStartY = frameStartPoint.y + margin[0];
				float frameIconEndX = frameIconStartX + iconSize[0];
				float frameIconEndY = frameIconStartY + iconSize[1];
				
				RectF iconFrame = new RectF(frameIconStartX, frameIconStartY, frameIconEndX, frameIconEndY);
				
				drawIcon(canvas, iconFrame, i);
				
				Rect bound = new Rect();
				textPaint.getTextBounds(label[i], 0, label[i].length(), bound);
				
				// draw text
				canvas.drawText(label[i], frameIconEndX + textMargin[1], frameIconStartY + textMargin[0] + bound.height() / 2 + iconSize[1] / 2, textPaint);
			}
		}
		
		void renderAroundLegend(Canvas canvas) {
			
			String[] label = getGraphLabel();
			
			for (int i = 0; i < NUMBER_OF_SENTIMENTS; i++) {
				
				Point frameStartPoint = getLegendCoor(i);
				
				canvas.drawText(label[i], frameStartPoint.x, frameStartPoint.y, textPaint);
				
			}
		}
		
		Point getLegendCoor(int sentNo) {
			
			switch (legendType) {
				case RIGHT_SIDE:
					return new Point(getGraphCenter() + getGraphSize() / 2, getGraphSize() / 2 - NUMBER_OF_SENTIMENTS / 2 * legendRendered.getLegendRowHeight() + sentNo
							* (legendRendered.getLegendRowHeight() + LegendRenderer.ROW_MARGIN));
					
				case AROUND:
					Point point = getPointOnCircumference(getGraphCenter(), getGraphCenter(), 60 * sentNo + deltaAngle, getGraphSize() / 2 + legendRendered.getLegendWidth() / 3);
					point.x = point.x - legendRendered.getLegendWidth(sentNo) / 2;
					
					if (sentNo == 4) {
						point.y = point.y + legendRendered.getLegendRowHeight() / 2;
					}
					
					return point;
			}
			
			return null;
			
		}
		
		public String[] getCustomLabels() {
			return customLabels;
		}
		
		public void setCustomLabels(String[] customLabels) {
			this.customLabels = customLabels;
			
		}
		
		public int getDeltaAngle() {
			return deltaAngle;
		}
		
		public void setDeltaAngle(int deltaAngle) {
			this.deltaAngle = deltaAngle;
		}
		
	}
	
	/** KLucz do SH ustawien legendy */
	public static String SP_LEGEND_POS_KEY = "settings_legend_pos";
	
	/** Liczba sentymentów */
	protected int NUMBER_OF_SENTIMENTS = 6;
	
	/** Kolory na wykresie dla poszczególnych sentymentów */
	protected static final int[] SENTIMENTS_COLORS = { 0xFFFF0000, 0xFFA523AA, 0xFF0000FF, 0xFF0FA40A, 0xFF1FA0F0, 0xFFAF501F };
	
	/** Szerokosc Canvas */
	protected int canvasWidth;
	
	/** Wysokosc Canvas */
	protected int canvasHeight;
	
	protected static String[] preferenceLegendTypes = { "None", "Right side", "Around", };
	
	/** enum Typ wykresu */
	public enum LegendTypes {
		NONE, RIGHT_SIDE, AROUND
	};
	
	/** Typ wykresu */
	protected LegendTypes legendType = LegendTypes.NONE;
	
	/** Dane do wykresu (wartosci sentymentow) */
	protected float[] sentValues = { 1.0f, 0.6f, 0.4f, 0.53f, 0.12f, 0.72f };
	
	/** Listener do klikniec */
	protected OnSentClickListener onSentClickListener;
	
	/** Legeng rendered */
	protected LegendRenderer legendRendered;
	
	protected Context context;
	
	private LegendTypeChangeListener legendTypeChangeListener = new LegendTypeChangeListener() {
		
		public void onChange(LegendTypes legendType) {
			
			setLegendType(legendType);
						
		}
		
	};
	
	/**
	 * Konstruktor wymagany przez klase View
	 * 
	 * @param context
	 * @param attrs
	 */
	public SentGraph(Context context, AttributeSet attrs) {
		super(context, attrs);
		this.context = context;
		
		// legenda
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
		String legendPos = prefs.getString(SP_LEGEND_POS_KEY, null);
		
		if (legendPos != null) {
			
			setLegendType(getLegendTypeFromString(legendPos));
			
		}
	}
	
	/**
	 * Zwraca pozycje punktu na obwodzie koła
	 * 
	 * @param centerX
	 * @param centerY
	 * @param angle
	 * @param distance
	 * @return
	 */
	protected Point getPointOnCircumference(float centerX, float centerY, int angle, float radius) {
		
		angle = (angle + 120) % 360;
		float angleRad = (float) ((angle / 180.0) * Math.PI);
		
		int x = (int) Math.round(centerX + radius * Math.sin(angleRad));
		int y = (int) Math.round(centerY - radius * Math.cos(angleRad));
		
		return new Point(x, y);
		
	}
	
	/**
	 * Callback na zmiane rozmiarow canvasa (Wywolywany przed onDraw)
	 */
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		
		canvasWidth = w;
		canvasHeight = h;
		
	}
	
	int getGraphCenter() {
		
		switch (legendType) {
			case RIGHT_SIDE:
				return Math.min(canvasWidth - legendRendered.getLegendWidth(), canvasHeight) / 2;
				
			default:
				return Math.min(canvasWidth, canvasHeight) / 2;
				
		}
		
	}
	
	int getGraphSize() {
		
		switch (legendType) {
			case AROUND:
				return 2 * (getGraphCenter() - legendRendered.getLegendWidth() / 2);
				
			default:
				return 2 * getGraphCenter();
				
		}
		
	}
	
	public LegendTypes getLegendType() {
		return legendType;
	}
	
	public void setLegendType(LegendTypes legendType) {
		this.legendType = legendType;
	}
	
	public OnSentClickListener getOnSentClickListener() {
		return onSentClickListener;
	}
	
	public void setOnSentClickListener(OnSentClickListener onSentClickListener) {
		this.onSentClickListener = onSentClickListener;
	}
	
	int getSentColorWithAlpha(int sentNo, int alpha) {
		
		int color = SENTIMENTS_COLORS[sentNo];
		
		color = color & 0x00FFFFFF;
		
		color = color | (alpha * (int) Math.pow(2, 24));
		
		return color;
		
	}
	
	public boolean onTouchEvent(MotionEvent event) {
		super.onTouchEvent(event);
		
		if (event.getAction() == MotionEvent.ACTION_UP) {
			
			if (onSentClickListener != null) {
				
				float x = event.getX();
				float y = event.getY();
				
				selectSentiment(getClickedSentNumber(x, y));
				
			}
			
		}
		return true;
	}
	
	protected void onAttachedToWindow() {
		super.onAttachedToWindow();
		
		ArrayList<LegendTypeChangeListener> legendTypeChangelListeners = ((StockSenseState) context.getApplicationContext()).getLegendTypeChangelListeners();
		
		legendTypeChangelListeners.add(legendTypeChangeListener);
		
	}
	
	protected void onDetachedFromWindow() {
		super.onDetachedFromWindow();
		
		ArrayList<LegendTypeChangeListener> legendTypeChangelListeners = ((StockSenseState) context.getApplicationContext()).getLegendTypeChangelListeners();
		
		legendTypeChangelListeners.remove(legendTypeChangeListener);
	}
	
	int getClickedSentNumber(float x, float y) {
		
		return 0;
		
	}
	
	public static LegendTypes getLegendTypeFromString(String string) {
		
		LegendTypes legendType;
		
		if (string.equals(preferenceLegendTypes[LegendTypes.RIGHT_SIDE.ordinal()]))
			legendType = LegendTypes.RIGHT_SIDE;
		else if (string.equals(preferenceLegendTypes[LegendTypes.AROUND.ordinal()]))
			legendType = LegendTypes.AROUND;
		else
			legendType = LegendTypes.NONE;
		
		return legendType;
		
	}
	
	void selectSentiment(int sentNo) {
		
	}
	
	public float[] getSentValues() {
		return sentValues;
	}
	
	public void setSentValues(float[] sentValues) {
		this.sentValues = sentValues;
	}
	
	public int getNumberOfSentiments() {
		return NUMBER_OF_SENTIMENTS;
	}
	
	public LegendRenderer getLegendRendered() {
		return legendRendered;
	}
	
	public void setLegendRendered(LegendRenderer legendRendered) {
		this.legendRendered = legendRendered;
	}
	
}
